﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Net;
using System.Web;

using WebServer.HTDOCS;

namespace WebServer.Modules
{
	/// <summary>
	/// Provides the means to register, track and retrieve static and virtual wrb-pages
	/// </summary>
	[CoreModule("WebObjects", typeof(WebObjects), CoreModulePriority.High)]
	public static class WebObjects
	{
		/// <summary>
		/// The virtual web-webObj registry, this stores all constructable virtual web-webObj information
		/// </summary>
		private static Dictionary<string, Type> _Registry = new Dictionary<string, Type>();

		/// <summary>
		/// Initialize all WebServer internal virtual web-pages
		/// </summary>
		private static void Start()
		{
			try
			{
				Type[] ats = new Type[0];
				Type[] cts = new Type[0];
				List<Type> lts = new List<Type>();

				ats = Assembly.GetAssembly(typeof(WebObject)).GetTypes();

				if (Core.CustomAssembly != null)
					cts = Core.CustomAssembly.GetTypes();

				for (int i = 0; i < ats.Length; i++)
					lts.Add(ats[i]);

				for (int i = 0; i < cts.Length; i++)
					lts.Add(cts[i]);

				Type[] ts = lts.ToArray();

				for (int i = 0; i < ts.Length; i++)
				{
					Register(ts[i]);
				}
			}
			catch (Exception ex)
			{
				Core.ConsoleWriteLine("*** WARNING: FATAL EXCEPTION THROWN ***");
				Core.ConsoleWriteLine("*** {0} ***", ex);
				Core.ConsoleWriteLine("***************************************");
				Core.WaitForKeyPress("Press any key to continue.");
			}
		}

		/// <summary>
		/// Registers a virtual web-webObj to the virtual registry, this should be used externally when WebServer is embedded into another application
		/// </summary>
		/// <param name="pType">Type of the webObj to construct</param>
		public static void Register(Type pType)
		{
			if (!pType.IsAbstract && pType.IsSubclassOf(typeof(WebObject)))
			{
				IWebObject webObj;

				try
				{
					string vPath = String.Empty;

					string[] split = pType.Namespace.Split('.');

					if (split.Length > 1 && split[0] == "WebServer" && split[1] == "HTDOCS")
					{
						for (int j = 0; j < split.Length; j++)
						{
							if (String.IsNullOrEmpty(split[j]))
								continue;

							vPath += String.Format("{0}\\", split[j]);
						}

						ConstructorInfo info = pType.GetConstructor(new Type[] { typeof(HttpListenerContext), typeof(Client), typeof(Uri) });
						ConstructorInfo uidInfo = pType.GetConstructor(new Type[] { typeof(UID) });

						if (uidInfo == null)
						{
							Core.ConsoleWriteLine("*** WARNING: NO CONSTRUCTOR TAKING 'UID uid' ARGUMENTS ***");
							Core.ConsoleWriteLine("*** {0} ***", pType.FullName);
							Core.ConsoleWriteLine("***************************************");
							Core.WaitForKeyPress("Press any key to continue.");
						}
						else if (info == null)
						{
							Core.ConsoleWriteLine("*** WARNING: NO CONSTRUCTOR TAKING 'HttpListenerContext ctx, Client client, Uri url' ARGUMENTS ***");
							Core.ConsoleWriteLine("*** {0} ***", pType.FullName);
							Core.ConsoleWriteLine("***************************************");
							Core.WaitForKeyPress("Press any key to continue.");
						}
						else
						{
							webObj = uidInfo.Invoke(new object[] { new UID(pType.FullName) }) as IWebObject;

							if (webObj != null)
								Register(vPath, webObj.VirtualName, pType);
						}
					}
					else
					{
						Core.ConsoleWriteLine("*** WARNING: WEBOBJECT CLASS NOT WITHIN 'WebServer.HTDOCS' NAMESPACE ***");
						Core.ConsoleWriteLine("*** {0} ***", pType.FullName);
						Core.ConsoleWriteLine("***************************************");
						Core.WaitForKeyPress("Press any key to continue.");
					}
				}
				catch (Exception ex1)
				{
					Core.ConsoleWriteLine("*** WARNING: FATAL EXCEPTION THROWN ***");
					Core.ConsoleWriteLine("*** {0} ***", pType.FullName);
					Core.ConsoleWriteLine("*** {0} ***", ex1);
					Core.ConsoleWriteLine("***************************************");
					Core.WaitForKeyPress("Press any key to continue.");
				}

				webObj = null;
			}
		}

		/// <summary>
		/// Registers a virtual webObj to the virtual registry, this should only be used internally by the WebServer system
		/// </summary>
		/// <param name="vPath">Virtual full path to access this webObj</param>
		/// <param name="name">Name of the webObj</param>
		/// <param name="pType">Type of the webObj to construct</param>
		public static void Register(string vPath, string name, Type pType)
		{
			string searchPath = vPath + name;

			//Core.ConsoleWriteLine("Registered Path: {0}", searchPath);

			if (!_Registry.ContainsKey(searchPath))
			{ _Registry.Add(searchPath, pType); }
			else
			{ _Registry[searchPath] = pType; }
		}

		public static Type GetTypeReference(string vPath)
		{
			if (_Registry.ContainsKey(vPath))
				return _Registry[vPath];

			return null;
		}

		public static IWebObject CreateInstance(Type type, HttpListenerContext ctx, Client client, Uri url)
		{
			try
			{ return (IWebObject)type.GetConstructor(new Type[] { typeof(HttpListenerContext), typeof(Client), typeof(Uri) }).Invoke(new object[] { ctx, client, url }); }
			catch
			{ }

			return null;
		}
	}
}
